package service

import (
	"context"
	"encoding/json"
	"fmt"
	common "golang_start/common"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
)

func init() {

}

//gorm.Model
/*时间结构体-固定名称*/
type CodeTypeParsertime string
type CodeCreate time.Time
type CodeType struct {
	Id int `gorm:"primaryKey" form:"id" json:"id,string"`

	Pid int `gorm:"column:pid" json:"pid" form:"pid"` //pid

	User_id int `gorm:"column:user_id" json:"user_id" form:"user_id"` //用户ID

	Type_title string `gorm:"column:type_title" json:"type_title" form:"type_title"` //分类名称

	Type_desc string `gorm:"column:type_desc" json:"type_desc" form:"type_desc"` //分类简介

	Type_icon string `gorm:"column:type_icon" json:"type_icon" form:"type_icon"` //分类图标

	Type_content string `gorm:"column:type_content" json:"type_content" form:"type_content"` //分类内容

	Sort int `gorm:"column:sort" json:"sort" form:"sort"` //排序

	Status int `gorm:"column:status" json:"status" form:"status"` //是否展示:1=显示,0=隐藏

	Created_at int `gorm:"autoCreateTime" form:"created_at"`

	Updated_at int `gorm:"autoUpdateTime" form:"updated_at"`

	Deleted_at gorm.DeletedAt `gorm:"deleted_at" json:"deleted_at" comment:"数据库类型必须为：datetime时间格式为2006-01-02 15:04:05"` //删除时间

	StatusText string `gorm:"-" json:"status_text"`
}

type CodeTypeInfinite struct {
	Id int `form:"id" json:"id"`

	Pid int ` json:"pid" form:"pid"` //pid

	User_id int ` json:"user_id" form:"user_id"` //用户ID

	Type_title string `json:"type_title" form:"type_title"` //分类名称

	Type_desc string ` json:"type_desc" form:"type_desc"` //分类简介

	Type_icon string `json:"type_icon" form:"type_icon"` //分类图标

	Type_content string ` json:"type_content" form:"type_content"` //分类内容

	Sort int `json:"sort" form:"sort"` //排序

	Status int

	// Created_at int

	Updated_at int

	StatusText string

	Value int `json:"value"`

	Label string `json:"label"`

	Children []CodeTypeInfinite ` json:"children"` //排序
}

func (pt *CodeCreate) MarshalJSON() ([]byte, error) {

	times := time.Time(*pt)
	return []byte(fmt.Sprintf("\"%v\"", times.Format("2006-01-02 15:04:05"))), nil
}

//删除的结构体
type CodeTypeDeleteids struct {
	Ids string `form:"ids" json:"ids" comment:"删除ID" validate:"required"`
}

/*指定表名-*/
func (model *CodeType) TableName() string {
	return "code_type"
}

/*Type类型*/
//是否展示:1=显示,0=隐藏
var StatusTextType = map[string]string{"1": "显示", "0": "隐藏"}

/***********时间转换************/
// func (pt CodeTypeParsertime) Value() (driver.Value, error) {

// 	pt_str := fmt.Sprintf("%v", pt)

// 	if pt_str == "" {
// 		return nil, nil
// 	}
// 	stime, _ := time.ParseInLocation("2006-01-02 15:04:05", string(pt), time.Local)

// 	val := stime.Unix()
// 	return val, nil
// }

// func (pt *CodeTypeParsertime) Scan(v interface{}) error {
// 	var str int64
// 	switch v.(type) {
// 	case int64:
// 		str = v.(int64)
// 	default:
// 		str, _ = strconv.ParseInt(string(v.([]byte)), 10, 64)
// 	}
// 	result := time.Unix(str, 0).Format("2006-01-02 15:04:05")
// 	*pt = CodeTypeParsertime(result)
// 	return nil
// }

/******************类型转换**********************/
func (model *CodeType) AfterFind(tx *gorm.DB) error {
	var vt, val, status_val string
	var ok bool

	vt = reflect.ValueOf(model.Status).Kind().String()
	if vt == "int" {
		status_val = strconv.FormatInt(int64(model.Status), 10)
	} else {
		status_val = StatusTextType[string(model.Status)]
	}
	val, ok = StatusTextType[status_val]
	if ok {
		model.StatusText = val
	}

	return nil
}

/*添加*/

func (model *CodeType) Add_(c context.Context, param *CodeType) (int, error) {

	err := common.DB.WithContext(c).Save(param).Error
	if err != nil {
		return 0, err
	}

	return param.Id, nil
}

/*删除*/
func (model *CodeType) Delete_(c context.Context, delete_ids *CodeTypeDeleteids) (int, error) {
	ids := strings.Split(delete_ids.Ids, ",")
	err := common.DB.WithContext(c).Where("id in (?)", ids).Delete(&CodeType{}).Error
	if err != nil {
		return 0, err
	}
	return 1, nil
}

/*修改*/
func (model *CodeType) Update_(c context.Context, update_data *CodeType) (int, error) {

	err := common.DB.Model(&CodeType{}).Where("id = ?", update_data.Id).Updates(&update_data).Error
	if err != nil {
		return 0, err
	}
	return 1, nil
}

/*查询(单条)*/
func (model *CodeType) Detail_(c context.Context, data *CodeType) (*CodeType, error) {
	result := common.DB.WithContext(c)
	err := result.Where("id = ?", data.Id).First(&data).Error
	if err != nil {
		return nil, err
	}
	return data, nil
}

/*多条查询ID**/
func (model *CodeType) FindByIds(c *gin.Context, id []string) ([]*CodeType, error) {
	var list = make([]*CodeType, 0)
	err := common.DB.WithContext(c).Table(model.TableName()).Where("id in (?)", id).Find(&list).Error
	if err != nil {
		return nil, err
	}
	return list, nil
}

/*查询-无极分类*/

func (model *CodeType) Catelist_(c *gin.Context) ([]CodeTypeInfinite, error) {
	result := common.DB.WithContext(c)
	// var list = []CodeTypeInfinite{}
	pid, _ := strconv.Atoi(c.DefaultQuery("pid", "0"))
	// result.Table("code_type").Where(CodeType{Pid: pid}).Find(&list)
	// fmt.Println(list)

	allData := []CodeType{}

	result.Where(CodeType{User_id: 1}).Order("sort desc").Find(&allData)

	sort_data := cate_sort(allData, pid)
	// fmt.Println(sort_data)
	return sort_data, nil
}

/*取地址排序*/

/*递归排序
 */
func cate_sort(alldata []CodeType, pid int) []CodeTypeInfinite {
	var child []CodeTypeInfinite

	for _, v := range alldata {
		if v.Pid == pid {

			son := cate_sort(alldata, v.Id)
			newson := CodeTypeInfinite{
				Id:           v.Id,
				Pid:          v.Pid,
				User_id:      v.User_id,
				Type_title:   v.Type_title,
				Type_desc:    v.Type_desc,
				Type_icon:    v.Type_icon,
				Type_content: v.Type_content,
				Sort:         v.Sort,
				Status:       v.Status,
				// Created_at:   v.Created_at,
				Updated_at: v.Updated_at,
				StatusText: v.StatusText,
				Children:   son,
				Value:      v.Id,
				Label:      v.Type_title,
			}
			child = append(child, newson)

		}
	}
	return child
}

/*查询列表*/
func (model *CodeType) List_(c context.Context, param map[string]string) ([]CodeType, int64, error) {
	result := common.DB.WithContext(c)
	var count int64
	var list = []CodeType{}

	Psize, _ := strconv.Atoi(param["psize"])
	Pindex, _ := strconv.Atoi(param["pindex"])

	if Pindex <= 0 {
		Pindex = 0
	}

	Pindex = (Pindex - 1) * Psize

	Order_column, _ := param["order"]

	Order_sort, _ := param["order_sort"]
	if Order_column == "" {
		Order_column = "id"
	}
	if Order_sort == "" {
		Order_sort = "desc"
	}
	result = result.Order(Order_column + " " + Order_sort)

	err := result.Limit(Psize).Offset(Pindex).Find(&list).Limit(-1).Offset(-1).Count(&count).Error

	export_json, _ := param["export_json"]

	if export_json != "" {
		reflect_struct := CodeType{}
		reflect_type := reflect.TypeOf(reflect_struct)
		var value_T []string
		resultarr := make(map[string]string)
		err = json.Unmarshal([]byte(export_json), &resultarr)
		if err != nil {
			fmt.Println(err.Error())
		} else {
			var title_T []string
			for i := 0; i < reflect_type.NumField(); i++ {
				nameValue := reflect_type.Field(i)
				json_key := nameValue.Tag.Get("json")
				val, ok := resultarr[json_key]
				if ok {
					title_T = append(title_T, val)
					value_T = append(value_T, nameValue.Name)
				}
				// fmt.Println(nameValue.Name)
			}
			filepath := model.ExportData(title_T, value_T, &list)
			if filepath != "" {
				/*
				*两种方式
				 */
				// c.Header("Content-Type", "application/octet-stream")
				// c.Header("Content-Disposition", "attachment; filename="+path.Base(filepath))
				// c.Header("Content-Transfer-Encoding", "binary")
				// // r, _ := os.Open(filepath)
				// r, _ := os.ReadFile(filepath)
				// c.Data(common.SUCCESS_CODE, "application/octet-stream", r)
				// c.AbortWithStatusJSON(common.SUCCESS_CODE, gin.H{
				// 	"code":    common.SUCCESS_CODE,
				// 	"message": "code",
				// 	"data":    "Request is success",
				// })

				return list, count, nil
			}
		}
	}
	if err != nil {
		return nil, count, err
	}
	return list, count, nil
}

func (model *CodeType) ExportData(title []string, value_T []string, data *[]CodeType) string {
	/*
	* 创建Excel
	 */
	ef := excelize.NewFile()
	sw, err := ef.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println("创建Excel错误:", err.Error())
	}
	styleID, _ := ef.NewStyle(&excelize.Style{Font: &excelize.Font{Color: "#333333", Bold: true, Family: "微软雅黑", Size: 20}})
	row_title := make([]interface{}, 0)
	for _, v := range title {
		row_title = append(row_title, excelize.Cell{Value: v, StyleID: styleID})
	}
	err = sw.SetRow("A1", row_title)
	if err != nil {
		fmt.Println("设置Excel标题错误:", err.Error())
	}
	Dataout := make(chan []interface{}, 3)
	var swGroup sync.WaitGroup
	swGroup.Add(1)
	go func(data *[]CodeType) {
		for _, val := range *data {
			row := make([]interface{}, 0)
			valVal := reflect.ValueOf(val)
			for _, vv := range value_T {
				valeue_val := valVal.FieldByName(vv)
				row = append(row, valeue_val)
			}
			Dataout <- row
		}
		Dataout <- []interface{}{}
		swGroup.Done()
	}(data)
	swGroup.Add(1)
	go func(sw *excelize.StreamWriter) {
		index := 2
		for data := range Dataout {
			if len(data) == 0 {
				break
			}
			cell, err := excelize.CoordinatesToCellName(1, index)
			if err != nil {
				fmt.Println("错误", err.Error())
			}
			err = sw.SetRow(cell, data, excelize.RowOpts{Height: 20})
			if err != nil {
				fmt.Println("写入数据错误", err.Error())
			}
			index++
		}
		swGroup.Done()
	}(sw)

	swGroup.Wait()
	sw.Flush()
	pathYear := time.Now().Format("200601")
	pathDay := time.Now().Format("20060102")
	filepath := "./static/upload/" + (pathYear) + "/" + (pathDay)
	_ = os.MkdirAll(filepath, os.ModePerm)
	fileName := filepath + "/" + pathDay + strconv.FormatInt(time.Now().Unix(), 10) + ".xlsx"
	err = ef.SaveAs(fileName)
	if err != nil {
		fmt.Println("保存Excel文件错误:,", err.Error())
	}
	defer func() {
		ef.Close()
		close(Dataout)
	}()
	return fileName
}
